/**
 *	LISTENER.C - implementation of LISTENER.H
 *	Author: Fabio Garcia <fabio@blastpress.com>
 **/

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "listener.h"
#include "utilities.h"
#include "handler.h"

int ListenForPeers() {
	int listener, connection;
	pid_t pid;
	struct sockaddr_in server_addr;

	/** create listener socket **/
	if((listener = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		ErrorQuit("Unable to create listener socket.");
	}

	/** populate server address structur **/
	memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_addr.sin_port = htons(LISTEN_PORT);

	/** assign socket address to sock **/
	if((bind(listener, (struct sockaddr*)&server_addr, sizeof(server_addr))) < 0) {
		ErrorQuit("Unable to bind listening socket.");
	}

	/** make socket a listening socket **/
	if((listen(listener, LISTENQ)) < 0) {
		ErrorQuit("Unable to make socket listen.");
	}

	/** loop indefinitely to accept and service connections **/
	while(1) {
		/** wait for connections **/
		if((connection = accept(listener, NULL, NULL)) < 0) {
			ErrorQuit("Error calling accept");
		}

		/** fork child process to service connection **/
		if((pid = fork()) == 0) {
			/** now in child process **/
			if((close(listener)) <0) {
				ErrorQuit("Unable to close listening socket.");
			}
			HandleConnection(connection);
			/** close socket and exit **/
			if((close(connection)) < 0) {
				ErrorQuit("Unable to close connecting socket.");
			}
			exit(EXIT_SUCCESS);
		}

		/** if we are still here we are in the parent process, so close the connection and clean up, then wait for a new conneciton **/
		if((close(connection)) < 0) {
			ErrorQuit("Unable to close connecting socket.");
		}
		waitpid(-1, NULL, WNOHANG);
	}
	return EXIT_FAILURE;
}
